{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 在Python中使用我们训练好点模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "前面我们实现了`汉字位置检测`和`汉字分类识别`模型，实际使用肯定要结合封装成接口来使用，会比较方便。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在darknet的官方项目中，已经为我们提供了一个demo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ctypes import *\n",
    "import math\n",
    "import random\n",
    "\n",
    "def sample(probs):\n",
    "    s = sum(probs)\n",
    "    probs = [a/s for a in probs]\n",
    "    r = random.uniform(0, 1)\n",
    "    for i in range(len(probs)):\n",
    "        r = r - probs[i]\n",
    "        if r <= 0:\n",
    "            return i\n",
    "    return len(probs)-1\n",
    "\n",
    "def c_array(ctype, values):\n",
    "    arr = (ctype*len(values))()\n",
    "    arr[:] = values\n",
    "    return arr\n",
    "\n",
    "class BOX(Structure):\n",
    "    _fields_ = [(\"x\", c_float),\n",
    "                (\"y\", c_float),\n",
    "                (\"w\", c_float),\n",
    "                (\"h\", c_float)]\n",
    "\n",
    "class DETECTION(Structure):\n",
    "    _fields_ = [(\"bbox\", BOX),\n",
    "                (\"classes\", c_int),\n",
    "                (\"prob\", POINTER(c_float)),\n",
    "                (\"mask\", POINTER(c_float)),\n",
    "                (\"objectness\", c_float),\n",
    "                (\"sort_class\", c_int)]\n",
    "\n",
    "\n",
    "class IMAGE(Structure):\n",
    "    _fields_ = [(\"w\", c_int),\n",
    "                (\"h\", c_int),\n",
    "                (\"c\", c_int),\n",
    "                (\"data\", POINTER(c_float))]\n",
    "\n",
    "class METADATA(Structure):\n",
    "    _fields_ = [(\"classes\", c_int),\n",
    "                (\"names\", POINTER(c_char_p))]\n",
    "\n",
    "    \n",
    "\n",
    "lib = CDLL(\"libdarknet.so\", RTLD_GLOBAL) # 配置so文件路径，最好是绝对路径\n",
    "lib.network_width.argtypes = [c_void_p]\n",
    "lib.network_width.restype = c_int\n",
    "lib.network_height.argtypes = [c_void_p]\n",
    "lib.network_height.restype = c_int\n",
    "\n",
    "predict = lib.network_predict\n",
    "predict.argtypes = [c_void_p, POINTER(c_float)]\n",
    "predict.restype = POINTER(c_float)\n",
    "\n",
    "set_gpu = lib.cuda_set_device\n",
    "set_gpu.argtypes = [c_int]\n",
    "\n",
    "make_image = lib.make_image\n",
    "make_image.argtypes = [c_int, c_int, c_int]\n",
    "make_image.restype = IMAGE\n",
    "\n",
    "get_network_boxes = lib.get_network_boxes\n",
    "get_network_boxes.argtypes = [c_void_p, c_int, c_int, c_float, c_float, POINTER(c_int), c_int, POINTER(c_int)]\n",
    "get_network_boxes.restype = POINTER(DETECTION)\n",
    "\n",
    "make_network_boxes = lib.make_network_boxes\n",
    "make_network_boxes.argtypes = [c_void_p]\n",
    "make_network_boxes.restype = POINTER(DETECTION)\n",
    "\n",
    "free_detections = lib.free_detections\n",
    "free_detections.argtypes = [POINTER(DETECTION), c_int]\n",
    "\n",
    "free_ptrs = lib.free_ptrs\n",
    "free_ptrs.argtypes = [POINTER(c_void_p), c_int]\n",
    "\n",
    "network_predict = lib.network_predict\n",
    "network_predict.argtypes = [c_void_p, POINTER(c_float)]\n",
    "\n",
    "reset_rnn = lib.reset_rnn\n",
    "reset_rnn.argtypes = [c_void_p]\n",
    "\n",
    "load_net = lib.load_network\n",
    "load_net.argtypes = [c_char_p, c_char_p, c_int]\n",
    "load_net.restype = c_void_p\n",
    "\n",
    "do_nms_obj = lib.do_nms_obj\n",
    "do_nms_obj.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]\n",
    "\n",
    "do_nms_sort = lib.do_nms_sort\n",
    "do_nms_sort.argtypes = [POINTER(DETECTION), c_int, c_int, c_float]\n",
    "\n",
    "free_image = lib.free_image\n",
    "free_image.argtypes = [IMAGE]\n",
    "\n",
    "letterbox_image = lib.letterbox_image\n",
    "letterbox_image.argtypes = [IMAGE, c_int, c_int]\n",
    "letterbox_image.restype = IMAGE\n",
    "\n",
    "load_meta = lib.get_metadata\n",
    "lib.get_metadata.argtypes = [c_char_p]\n",
    "lib.get_metadata.restype = METADATA\n",
    "\n",
    "load_image = lib.load_image_color\n",
    "load_image.argtypes = [c_char_p, c_int, c_int]\n",
    "load_image.restype = IMAGE\n",
    "\n",
    "rgbgr_image = lib.rgbgr_image\n",
    "rgbgr_image.argtypes = [IMAGE]\n",
    "\n",
    "predict_image = lib.network_predict_image\n",
    "predict_image.argtypes = [c_void_p, IMAGE]\n",
    "predict_image.restype = POINTER(c_float)\n",
    "\n",
    "def classify(net, meta, im):\n",
    "    out = predict_image(net, im)\n",
    "    res = []\n",
    "    for i in range(meta.classes):\n",
    "        res.append((meta.names[i], out[i]))\n",
    "    res = sorted(res, key=lambda x: -x[1])\n",
    "    return res\n",
    "\n",
    "def detect(net, meta, image, thresh=.5, hier_thresh=.5, nms=.45):\n",
    "    im = load_image(image, 0, 0)\n",
    "    num = c_int(0)\n",
    "    pnum = pointer(num)\n",
    "    predict_image(net, im)\n",
    "    dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, None, 0, pnum)\n",
    "    num = pnum[0]\n",
    "    if (nms): do_nms_obj(dets, num, meta.classes, nms);\n",
    "\n",
    "    res = []\n",
    "    for j in range(num):\n",
    "        for i in range(meta.classes):\n",
    "            if dets[j].prob[i] > 0:\n",
    "                b = dets[j].bbox\n",
    "                res.append((meta.names[i], dets[j].prob[i], (b.x, b.y, b.w, b.h)))\n",
    "    res = sorted(res, key=lambda x: -x[1])\n",
    "    free_image(im)\n",
    "    free_detections(dets, num)\n",
    "    return res\n",
    "\n",
    "def run():\n",
    "    net = load_net(\n",
    "        \"\".encode(), # cfg文件路径\n",
    "        \"\".encode(), # weights权重文件路径\n",
    "        0  # 默认0\n",
    "    )\n",
    "    meta = load_meta(\"\".encode()) # data文件路径\n",
    "    # 执行预测\n",
    "    r = detect(\n",
    "        net, \n",
    "        meta, \n",
    "        \"\".encode()\n",
    "    )\n",
    "    print(r)\n",
    "    \n",
    "    \n",
    "if __name__ == \"__main__\":\n",
    "    run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里几个要注意的点：\n",
    "\n",
    "- 文件路径编码\n",
    "- libdarknet.so 文件的路径配置"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "blog",
   "language": "python",
   "name": "blog"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
